#include "QtSerialization.h"

QDataStream &operator << ( QDataStream& out, const fl_NtcStg& stg )
{
    out << qint32(stg.getFlag());
    return out;
}

QDataStream &operator >> ( QDataStream&  in, fl_NtcStg& stg )
{
    qint32 fl;
    in >> fl;
    stg.setFlag(fl);
    return in;
}

QDataStream &operator << ( QDataStream& out, const fl_NtcTpg& tpg )
{
    out << qint32(tpg.getFlag());
    return out;
}

QDataStream &operator >> ( QDataStream&  in, fl_NtcTpg& tpg )
{
    qint32 fl;
    in >> fl;
    tpg.setFlag(fl);
    return in;
}

QDataStream &operator<<(QDataStream &out, const TpSLsismico &sls)
{
    out << sls.isCustom() << sls.getFlagValue() << qint32(sls.getFlag());
    return out;
}

QDataStream &operator>>(QDataStream &in, TpSLsismico &sls)
{
    bool is_custom;
    double pvr;
    int flag;

    in >> is_custom >> pvr >> flag;
    sls = is_custom ? TpSLsismico(pvr) : TpSLsismico(flag);
    return in;
}

QDataStream &operator<<(QDataStream &out, const TpCostruzione &co)
{
    out << co.isCustom() << co.getFlagValue() << qint32(co.getFlag());
    return out;
}

QDataStream &operator>>(QDataStream &in, TpCostruzione &co)
{
    bool is_custom;
    double vn;
    int flag;

    in >> is_custom >> vn >> flag;
    co = is_custom ? TpCostruzione(vn) : TpCostruzione(flag);
    return in;
}

QDataStream &operator<<(QDataStream &out, const TpClasseUso &tpcu)
{
    out << tpcu.isCustom() << tpcu.getFlagValue() << qint32(tpcu.getFlag());
    return out;
}

QDataStream &operator>>(QDataStream &in, TpClasseUso &tpcu)
{
    bool is_custom;
    double cu;
    int flag;

    in >> is_custom >> cu >> flag;
    tpcu = is_custom ? TpClasseUso(cu) : TpClasseUso(flag);
    return in;
}

QDataStream& operator << (QDataStream& out, const PKeyItem& key )
{
    out << QSTR(key.getKeyStr());
    out << QSTR(key.getDescr());
    out << key.getTabRef();
    return out;
}

QDataStream& operator >> ( QDataStream& in, PKeyItem& key )
{
    QString keys, descr;
    int tab_ref;
    in >> keys;
    in >> descr;
    in >> tab_ref;
    key.setKeyStr(keys.toStdString());
    key.setDescr(descr.toStdString());
    key.setTabRef(tab_ref);
    return in;
}

QDataStream& operator << ( QDataStream &out, const PItem &item )
{
    out << item.getTabRef();
    return out;
}

QDataStream& operator >> ( QDataStream  &in,       PItem &item )
{
    int tab_ref;
    in >> tab_ref;
    item.setTabRef(tab_ref);
    return in;
}

QDataStream& operator << ( QDataStream &out, const PKey &key )
{
    out << QSTR(key.getKeyStr());
    out << QSTR(key.getDescr());
    return out;
}

QDataStream& operator >> ( QDataStream  &in,       PKey &key )
{
    QString keys, descr;
    in >> keys;
    in >> descr;
    key.setKeyStr(keys.toStdString());
    key.setDescr(descr.toStdString());
    return in;
}

QDataStream& operator << ( QDataStream& out, const TempiRitorno& tr )
{
    operator << (out,PKeyItem(tr));
    out << tr.tp_co;
    out << tr.tp_cu;
    out << tr.tp_sls;
    out << tr.isCustom();
    out << tr.getFlagValue();
    return out;
}

QDataStream& operator >> ( QDataStream& in, TempiRitorno& tr )
{
    PKeyItem key;
    TpCostruzione co;
    TpClasseUso cu;
    TpSLsismico sls;
    bool custom;
    double value;

    in >> key;
    in >> co;
    in >> cu;
    in >> sls;
    in >> custom;
    in >> value;

    if (!custom){
        tr = TempiRitorno(cu,co,sls,key);
        tr.solverCheck();
        tr.solve();
    } else {
        tr = TempiRitorno(value,key);
    }
    return in;
}

QDataStream &operator<<(QDataStream &out, const EPoint &p)
{
    out << p.rif() << p.lon() << p.lat() << p.isNull_lon() << p.isNull_lat();
    return out;
}

QDataStream &operator>>(QDataStream &in, EPoint &p)
{
    int rif;
    double lon, lat;
    bool isNull_lon, isNull_lat;

    in >> rif >> lon >> lat >> isNull_lon >> isNull_lat;
    p = EPoint(lon,lat,rif);

    if (isNull_lon) p.setNull_lon();
    if (isNull_lat) p.setNull_lat();

    return in;
}

QDataStream& operator << (QDataStream &out, const PRef &ref)
{
    int nb_ref;
    nb_ref = ref.nbRefFrom();
    out << nb_ref;
    PRef copy_ref = ref;
    int i;
    for (i = 0; i < nb_ref; i++)
    {
        out << copy_ref[i];
    }
    return out;
}

QDataStream& operator >> (QDataStream &in, PRef &ref)
{
    int nb_ref;
    in >> nb_ref;
    ref[nb_ref-1];
    int i;
    for (i = 0; i < nb_ref; i++)
    {
        in >> ref[i];
    }
    return in;
}

QDataStream &operator << (QDataStream &out, const SpecParam& param)
{
    out << param.agn();
    out << param.Fo();
    out << param.Tsc();
    out << param.isCustom();
    operator << (out,PKeyItem(param));
    operator << (out,PRef(param));
    return out;
}

QDataStream &operator >> (QDataStream &in, SpecParam& param)
{
    double agn, Fo, Tsc;
    bool custom;
    PKeyItem key;
    PRef ref;

    in >> agn;
    in >> Fo;
    in >> Tsc;
    in >> custom;
    in >> key;
    in >> ref;

    param = SpecParam(agn,Fo,Tsc,key,ref);
    param.setCustom(custom);

    return in;
}

QDataStream &operator<<(QDataStream &out, const SeismicPoint &p)
{
    operator <<(out,EPoint(p));
    out << p.get_SpecParam(SeismicPoint::TR30);
    out << p.get_SpecParam(SeismicPoint::TR50);
    out << p.get_SpecParam(SeismicPoint::TR72);
    out << p.get_SpecParam(SeismicPoint::TR101);
    out << p.get_SpecParam(SeismicPoint::TR140);
    out << p.get_SpecParam(SeismicPoint::TR201);
    out << p.get_SpecParam(SeismicPoint::TR475);
    out << p.get_SpecParam(SeismicPoint::TR975);
    out << p.get_SpecParam(SeismicPoint::TR2475);
    return out;
}

QDataStream &operator>>(QDataStream &in, SeismicPoint &p)
{
    SpecParam sp30, sp50, sp72, sp101, sp140, sp201, sp475, sp975, sp2475;
    EPoint ep;
    operator >>(in,ep);
    in >> sp30 >> sp50 >> sp72 >> sp101 >> sp140 >> sp201 >> sp475 >> sp975 >> sp2475 ;
    p = SeismicPoint(ep,sp30,sp50,sp72,sp101,sp140,sp201,sp475,sp975,sp2475);
    return in;
}

QDataStream &operator<<( QDataStream& out, const SeismicSite& ss )
{
    operator << ( out, SeismicPoint(ss) );
    operator << ( out, PKeyItem(ss) );
    return out;
}

QDataStream &operator>>( QDataStream& in, SeismicSite& ss )
{
    SeismicPoint sp;
    PKeyItem key;
    operator >> ( in, sp );
    operator >> ( in, key );
    ss = SeismicSite( sp, key );
    return in;
}

QDataStream &operator<<(QDataStream &out, const SeismicLandmark &sl)
{
    operator <<(out,SeismicPoint(sl));
    out << sl.getId();
    return out;
}

QDataStream &operator>>(QDataStream &in, SeismicLandmark &sl)
{
    unsigned short id;
    SeismicPoint sp;
    operator >>(in,sp);
    in >> id ;
    sl = SeismicLandmark(sp,id);
    return in;
}


QDataStream &operator<<(QDataStream &out, const SeismicGrid &grid)
{
    operator << ( out, PKeyItem( grid ) );
    out << grid.P1 << grid.P2;
    out << grid.P3 << grid.P4 ;
    out << grid.site;
    out << grid.distanceFromP1() << grid.distanceFromP2() ;
    out << grid.distanceFromP3() << grid.distanceFromP4() ;
    out << grid.TpCalc();
    out << QString::fromStdString(grid.getImgName());
    out << grid.getImgPreview();
    // out << grid.IsControlled();
    return out;
}

QDataStream &operator>>(QDataStream &in, SeismicGrid &grid)
{
    PKeyItem key;
    operator >> ( in, key );
    grid.setKey(key);

    in >> grid.P1 >> grid.P2 >> grid.P3 >> grid.P4;
    in >> grid.site;

    double d;
    in >> d; grid.setDistanceFromP1(d);
    in >> d; grid.setDistanceFromP2(d);
    in >> d; grid.setDistanceFromP3(d);
    in >> d; grid.setDistanceFromP4(d);

    int tpcal;
    in >> tpcal; grid.setTpCalc(tpcal);

    QString imgName;
    in >> imgName; grid.setImgName(imgName.toStdString());

    bool imgPreview;
    in >> imgPreview; grid.setImgPreview(imgPreview);
    return in;
}

QDataStream &operator<<(QDataStream &out, const Ductility &ductility)
{
    out << ductility.getValue();
    return out;
}

QDataStream &operator>>(QDataStream &in, Ductility &ductility)
{
    double d;
    in >> d;
    ductility.setValue(d);
    return in;
}

QDataStream &operator<<(QDataStream &out, const Damping &damping)
{
    out << damping.getValue();
    return out;
}

QDataStream &operator>>(QDataStream &in, Damping &damping)
{
    double d;
    in >> d;
    damping.setValue(d);
    return in;
}

QDataStream &operator<<(QDataStream &out, const TpSpecDesign &tp)
{
    out << tp.getFlag();
    return out;
}

QDataStream &operator>>(QDataStream &in, TpSpecDesign &tp)
{
    int flag;
    in >> flag;
    tp.setFlag(flag);
    return in;
}

QDataStream &operator<<(QDataStream &out, const SpecDesign &sd)
{
    operator << ( out, PKeyItem(sd) );
    operator << ( out, PRef(sd) );
    operator << ( out, sd.getDamping() );
    operator << ( out, sd.getDuctility() );
    operator << ( out, sd.getTpSpecDesign() );
    return out;
}

QDataStream &operator>>(QDataStream &in, SpecDesign &sd)
{
            PKeyItem key;
            PRef ref;
         Damping dam;
       Ductility duc;
    TpSpecDesign tp_sd;

    operator >> ( in, key );
    operator >> ( in, ref );
    operator >> ( in, dam );
    operator >> ( in, duc );
    operator >> ( in, tp_sd );

    sd = SpecDesign(key,ref,dam,duc,tp_sd);

    return in;
}

QDataStream& operator << ( QDataStream& out, const TempiRitornoL& list )
{
    // salvo la lunghezza della lista
    int size = list.sizeOf();
    out << size;

    // salvo gli elementi della lista
    int i;
    for ( i = 0; i < size; ++i)
    {
        out << list.getAt(i);
    }
    return out;
}

QDataStream& operator >> ( QDataStream& in, TempiRitornoL& list )
{
    // recupero la lunghezza della lista
    int size;
    in >> size;

    // recupero gli elementi della lista
    TempiRitorno tr;
    int i;
    for ( i = 0; i < size; ++i)
    {
        in >> tr;
        list.insertAt(i,1);
        list.valueAt(i) = tr;
    }
    return in;
}

QDataStream& operator << ( QDataStream& out, const SpecParamL& list )
{
    // salvo la lunghezza della lista
    int size = list.sizeOf();
    out << size;

    // salvo gli elementi della lista
    int i;
    for ( i = 0; i < size; ++i)
    {
        out << list.getAt(i);
    }
    return out;
}

QDataStream& operator >> ( QDataStream& in, SpecParamL& list )
{
    // recupero la lunghezza della lista
    int size;
    in >> size;

    // recupero gli elementi della lista
    SpecParam sp;
    int i;
    for ( i = 0; i < size; ++i)
    {
        in >> sp;
        list.insertAt(i,1);
        list.valueAt(i) = sp;
    }
    return in;
}

QDataStream& operator << ( QDataStream& out, const PFileList& plist )
{
    // salvo la lunghezza della lista
    int size = plist.sizeOf();
    out << qint32(size);
    out << qint32(plist.getLastId());
    // salvo gli elementi della lista
    int i;
    for ( i = 0; i < size; i++)
    {
        out << plist.getAt(i);
        qDebug() << "OUTPUT index of =" << plist.getAt(i).getIndexOfModuleList();
    }
    return out;
}

QDataStream& operator >> ( QDataStream& in, PFileList& plist )
{
    // recupero la lunghezza della lista
    qint32 size, lastId;
    in >> size;
    in >> lastId;
    PFileList::setLastId(lastId);

    // recupero gli elementi della lista
    PFileItem pf;
    qint32 i;
    for ( i = 0; i < size; ++i)
    {
        in >> pf;
        plist.insertAt(i,1);
        plist.valueAt(i) = pf;

        // Assegno l'indice al modulo gestore della lista
        if (pf.isModuleCurrent())
        {
            AbstractModule* mod = AbstractModule::getModule(pf.getModuleType());
            if (mod)
            {
                mod->setIndexOfModuleList(i);
            }
        }
    }
    return in;
}

QDataStream& operator << ( QDataStream& out, const SpecDesignL& list )
{
    // salvo la lunghezza della lista
    int size = list.sizeOf();
    out << size;

    // salvo gli elementi della lista
    int i;
    for ( i = 0; i < size; ++i)
    {
        out << list.getAt(i);
    }
    return out;
}

QDataStream& operator >> ( QDataStream& in, SpecDesignL& list )
{
    // recupero la lunghezza della lista
    int size;
    in >> size;

    // recupero gli elementi della lista
    SpecDesign sd;
    int i;
    for ( i = 0; i < size; ++i)
    {
        in >> sd;
        list.insertAt(i,1);
        list.valueAt(i) = sd;
    }
    return in;
}

QDataStream &operator << ( QDataStream& out, const PTime& time )
{
    out << time.getHour();
    out << time.getMin();
    out << time.getSec();
    out << time.getDay();
    out << time.getMon();
    out << time.getYear();
    out << qint32(time.getTime());
    return out;
}

QDataStream &operator >> ( QDataStream&  in, PTime& time )
{
     int     hour; in >> hour;
     int      min; in >> min;
     int      sec; in >> sec;
     int      day; in >> day;
     int      mon; in >> mon;
     int     year; in >> year;
     qint32 _time; in >> _time;

    time = PTime(hour,min,sec,day,mon,year,long(_time));

    return in;
}

QDataStream &operator << ( QDataStream& out, const Elab& elab )
{
    out << QSTR(elab.getName());
    out << QSTR(elab.getTitle());
    out << elab.getTimeStart();
    out << elab.getTimeEnd();
    return out;
}

QDataStream &operator >> ( QDataStream&  in, Elab& elab )
{
    QString name, title;
    in >> name;
    in >> title;
    PTime start, end;
    in >> start;
    in >> end;
    elab = Elab(name.toStdString(),title.toStdString(),start,end);
    return in;
}

QDataStream &operator << ( QDataStream& out, const Work& work )
{
    out << QSTR(work.Id());
    out << QSTR(work.title());
    return out;
}

QDataStream &operator >> ( QDataStream&  in, Work& work )
{
    QString id, title;
    in >> id;
    in >> title;
    work = Work(title.toStdString(),id.toStdString());
    return in;
}

QDataStream &operator << ( QDataStream& out, const Comm& comm )
{
    out << QSTR(comm.Id());
    out << QSTR(comm.Name());
    out << QSTR(comm.Surname());
    return out;
}

QDataStream &operator >> ( QDataStream&  in, Comm& comm )
{
    QString id, name, surname;
    in >> id;
    in >> name;
    in >> surname;
    comm = Comm(name.toStdString(),surname.toStdString(),id.toStdString());
    return in;
}

QDataStream& operator << ( QDataStream &out, const PFileItem &item )
{
    operator << (out,PKeyItem(item));
    out << qint32(item.getModuleType());
    out << QSTR(item.getModuleFileName());
    out << item.isModuleCurrent();
    out << qint32(item.getIndexOfModuleList());
    operator << (out,PRef(item));
    return out;
}

QDataStream& operator >> ( QDataStream  &in, PFileItem &item )
{
    PKeyItem key_item;
    qint32 type;
    QString file_name;
    bool current;
    qint32 index;
    PRef ref;

    in >> key_item;
    in >> type;
    in >> file_name;
    in >> current;
    in >> index;
    in >> ref;

    item = PFileItem(
                PFileItem::moduleObj(type),
                file_name.toStdString(),
                current,
                ref
                );

    item.setKeyStr(key_item.getKeyStr());
    item.setDescr(key_item.getDescr());
    item.setTabRef(key_item.getTabRef());
    item.setIndexOfModuleList(index);

    return in;
}

QDataStream& operator << ( QDataStream &out, const ProjectData &prj_data )
{
    out << prj_data.getWork();
    out << prj_data.getComm();
    return out;
}

QDataStream& operator >> ( QDataStream  &in,       ProjectData &prj_data )
{
    Work work;
    Comm comm;
    in >> work;
    in >> comm;
    prj_data = ProjectData(work,comm);
    return in;
}


